package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"go.getaway.adminspro.padmins.com/bootstrap"
	"go.getaway.adminspro.padmins.com/untils"
	"go.getaway.adminspro.padmins.com/untils/auth"
	"go.getaway.adminspro.padmins.com/untils/businessCommonQuery"
	"go.getaway.adminspro.padmins.com/untils/config"
	"go.getaway.adminspro.padmins.com/untils/db"
	"go.getaway.adminspro.padmins.com/untils/handler"
	"go.getaway.adminspro.padmins.com/untils/request"
	"go.getaway.adminspro.padmins.com/untils/response"
	"log"
	"net/http"
	"runtime"
	"time"
)

func main() {

	Di := bootstrap.Run()
	http.Handle("/getaway", http.TimeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()

		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-methods", "POST, PUT, GET, OPTIONS, DELETE")
		w.Header().Set("Access-Control-Allow-Credentials", "true")
		w.Header().Set("Access-Control-Allow-Headers", "X-Requested-With,X_Requested_With,Authorization,Content-Type,token,Access-Token")

		if r.Method == "OPTIONS" {
			return
		}

		Request := request.NewRequest(r)
		Db := db.NewDb(Di.Get("dbConnect").(*db.DbConnect))
		c := &handler.Handler{
			Di:                  Di,
			Db:                  Db,
			Response:            response.NewHttpResponse(w),
			Request:             Request,
			Auth:                &auth.Auth{Di: Di, Db: Db},
			BusinessCommonQuery: &businessCommonQuery.BusinessCommonQuery{Di: Di, Request: Request},
		}

		resp := Di.Get("response").(*response.Response)
		method := c.Request.Params("method", "").(string)
		var m *response.Message
		if method == "" {
			m = resp.Error(10000, "method 参数不能为空")
		} else {
			routers := Di.Get("routers").(map[string]func(c *handler.Handler) (map[string]interface{}, untils.Error))
			if router, ok := routers[method]; ok {
				_, e := bootstrap.Permission(c)
				if e != nil {
					m = resp.Error(e.GetCode(), fmt.Sprintf("%v", e))
				} else {
					data, e := router(c)
					if e != nil {
						app_debug := Di.Get("config").(*config.Config).Get("app.debug")
						if app_debug == "1" {
							m = resp.Error(e.GetCode(), fmt.Sprintf("%v", e), e.Error())
						} else {
							m = resp.Error(e.GetCode(), fmt.Sprintf("%v", e))
						}
					} else {
						m = resp.Success(data)
					}
				}
			} else {
				m = resp.Error(10001, fmt.Sprintf("[%s] method 不存在", method))
			}
		}
		m.Runtime = fmt.Sprintf("%v", time.Since(start))
		w.Header().Set("Content-Type", "application/json;charset=utf-8")
		res := bytes.NewBuffer([]byte{})
		jsonEncoder := json.NewEncoder(res)
		jsonEncoder.SetEscapeHTML(false)
		e := jsonEncoder.Encode(m)

		if e != nil {
			fmt.Fprint(w, e)
		} else {
			fmt.Fprint(w, res)
		}
	}), 20*time.Second, ""))

	http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "pong")
	})

	http.HandleFunc("/routine", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json;charset=utf-8")
		fmt.Fprint(w, fmt.Sprintf("{\"routine\":%d}", runtime.NumGoroutine()))
	})
	c := Di.Get("config").(*config.Config)

	server := &http.Server{
		Addr:    c.Get("http.addr"),
		Handler: nil,
		// 从 Wait 到 Reqeust body 这一段的超时,
		// 如果我们把 ReadTimeout 设置成 50ms，那么客户端必须在 50 毫秒内将请求的 header 和 body 都发送给服务器，不然就会超时，服务器会取消整个处理过程
		ReadTimeout: time.Second * 2,
		// 服务端没法事先确定 header 部分数据的长度，只能一边接收一边解析。这样协议非常方便后续的升级和扩展，但让服务器非常被动。
		// 所以有必要为这个过程设置单独的超时时间。这个超时由 ReadHeaderTimeout 控制
		// 如果我们设置了 ReaderHeaderTimeout 为 10ms，那么客户端就必须在 10 毫秒内发完全部 header，不能磨磨蹭蹭。
		// 如果设置了 ReadTimeout 而没设置 ReadHeaderTimout，http.Server 会用 ReadTimeout 的值设置 ReadHeaderTimeout。
		ReadHeaderTimeout: time.Second * 2,
		// 服务器给客户端发送 Response 也需要控制超时。为什么呢？
		// 如果客户端的请求处理完成了，但就是不接收 Response 或者故意收的很慢，就会一直占用服务器资源。
		// 所以有必要「惩罚」那些慢吞吞和不怀好意的客户端
		// 如果将 WriteTimeout 设成 50ms，那客户端必须在 50 毫秒内接收所有响应数据，不然就取消整个处理过程。
		// 有一点注意，WriteTimeout 时间包含了读取 body 的时间。也就是说 ReadTimeout 和 WriteTimeout 的超时在读取 body 这部分是重叠的。
		WriteTimeout: time.Second * 5,
		// 控制的是 Idle 阶段的等待时间。如果一次请求结束后好长时间都没有收到新的请求，服务端就会主动关闭当前 TCP 连接，从而释放资源
		IdleTimeout: time.Second * 2,
	}
	// TimeoutHandler 控制的 Reqeust body 和 Response 这两个过程，也就是 ServeHTTP 过程
	// 如果整个过程超过指定的时间，http.Server 会直接返回 503 并取消整个处理过程
	// 如果其他配置项没有指定，http.Server 默认是不超时
	// 参考：https://taoshu.in/go/go-http-server-timeout.html?utm_source=wechat_session&utm_medium=social&utm_oi=1250124902713532416
	log.Fatal(server.ListenAndServe())
}
